﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace PitOfDespair.Dungeon
{
    /// <summary>
    /// http://stackoverflow.com/questions/4997642/simple-example-of-bsp-dungeon-generation
    /// </summary>
    class DungeonRectangle:IGenerationStrategy
    {
          private static int MIN_SIZE = 5;
    private static Random rnd = new Random(); 

    private int top, left, width, height;
    private DungeonRectangle leftChild;
    private DungeonRectangle rightChild;
    private DungeonRectangle dungeon;

    public DungeonRectangle(int top, int left, int height, int width)
    {
        this.top = top;
        this.left = left;
        this.width = width;
        this.height = height;
    }

     bool Split() {
        if( leftChild != null ) //if already split, bail out
            return false;
        var horizontal =rnd.Next(1)==1; //direction of split
        int max = (horizontal ? height : width ) - MIN_SIZE; //maximum height/width we can split off
        if( max <= MIN_SIZE ) // area too small to split, bail out
            return false;
        int split = rnd.Next( max ); // generate split point 
        if( split < MIN_SIZE )  // adjust split point so there's at least MIN_SIZE in both partitions
            split = MIN_SIZE;
        if( horizontal ) { //populate child areas
            leftChild = new DungeonRectangle(top, left, split, width);
            rightChild = new DungeonRectangle(top + split, left, height - split, width);
        } else {
            leftChild = new DungeonRectangle(top, left, height, split);
            rightChild = new DungeonRectangle(top, left + split, height, width - split);
        }
        return true; //split successful
    }

     void GenerateDungeon() {
        if( leftChild != null ) { //if current are has child areas, propagate the call
            leftChild.GenerateDungeon();
            rightChild.GenerateDungeon();
        } else { // if leaf node, create a dungeon within the minimum size constraints
            int dungeonTop = (height - MIN_SIZE <= 0) ? 0 : rnd.Next( height - MIN_SIZE);
            int dungeonLeft =  (width - MIN_SIZE <= 0) ? 0 : rnd.Next( width - MIN_SIZE);
            int dungeonHeight = Math.Max(rnd.Next( height - dungeonTop ), MIN_SIZE );;
            int dungeonWidth = Math.Max(rnd.Next( width - dungeonLeft ), MIN_SIZE );;
            dungeon = new DungeonRectangle(top + dungeonTop, left + dungeonLeft, dungeonHeight, dungeonWidth);
        }
    }

    #region IGenerationStrategy Members
        public Tuple<Location[,],int,int> Generate()
        {
            var x = rnd.Next(this.width);
            var y = rnd.Next(this.height);
            return Tuple.Create(Generate(x, y),x,y);
        }
    public Location[,] Generate(int startX,int startY)
    {
        var rectangles = new List<DungeonRectangle>(); // flat rectangle store to help pick a random one
        DungeonRectangle root = new DungeonRectangle(0, 0, 60, 120); //
        rectangles.Add(root); //populate rectangle store with root area
        while (rectangles.Count < 19)
        { // this will give us 10 leaf areas
            int splitIdx = rnd.Next(rectangles.Count-1); // choose a random element
            DungeonRectangle toSplit = rectangles[splitIdx];
            if (toSplit.Split())
            { //attempt to split
                rectangles.Add(toSplit.leftChild);
                rectangles.Add(toSplit.rightChild);
            }

        }
        root.GenerateDungeon();
        return null; //TODO: finish algorithm?
    }

    #endregion
    }
}
